/**
 * Copyright ©2003~2018年11月2日 szkingdom
 * @author raohj
 * @date 2018年11月2日
 * @file RNettyClient.java
 * @comment : please input your comment to this file
 * @version : input version
 * @modify:
 * 		1、 2018年11月2日 由 raohj 新建文件
 */
package com.ccnu.demojava.net.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.Charset;

/**
 * @author raohj
 * @date 2018年11月2日
 * @version
 * @comment to add your comment
 */

/**
 * @author raohj
 * @date 2018年11月2日
 * @version
 * @comment to add your comment
 */
public class RNettyLengthFieldClient{
	Logger log = LoggerFactory.getLogger(RNettyLengthFieldClient.class);
	private String host;
	private int port;
	private ByteBuf sendMsg;
	private ByteBuf recvMsg;
	
	public RNettyLengthFieldClient(String host, int port){
		this.host = host;		
		this.port = port;
	}
	
	public ByteBuf getSendMsg() {
		return sendMsg;
	}

	public void setSendMsg(ByteBuf sendMsg) {
		this.sendMsg = sendMsg;
	}
	
	public ByteBuf getRecvMsg() {
		return recvMsg;
	}

	public void setRecvMsg(ByteBuf recvMsg) {
		this.recvMsg = recvMsg;
	}
	
	// 通讯处理对象
	public class RClientHandler extends ChannelInboundHandlerAdapter{
		// 建立连接时，给服务器发送请求
		@Override
		public void channelActive(ChannelHandlerContext ctx) throws Exception {
			log.info("channelActive");
			Integer iLen = Integer.valueOf(sendMsg.readableBytes());
			ByteBuf sendBuf = Unpooled.buffer();
			sendBuf.writeInt(iLen);
			sendBuf.writeBytes(sendMsg);
			ChannelFuture f = ctx.channel().writeAndFlush(sendBuf);
			f.addListener( new ChannelFutureListener() {
				public void operationComplete(ChannelFuture future) throws Exception {
					log.info("发送给服务器的信息发送完毕");
				}
			});
		}
		
		// 超时处理对象
		@Override
		public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
			// TODO Auto-generated method stub
			log.info("userEventTriggered 触发了");
			if(evt instanceof IdleStateEvent) {
				IdleStateEvent e = (IdleStateEvent) evt;
				switch (e.state()) {
				case ALL_IDLE:
					log.info("ALL_IDLE");
					ctx.close();
					break;
				default:
					break;
				}
			}
		}
				
		// 读取服务器应答
		@Override
		public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {			
			log.info("channelRead");
			ByteBuf m = (ByteBuf)msg;
			
			try {
				setRecvMsg(m);
				log.info("recv from server:" + m.toString(Charset.forName("GBK")));
				
				ctx.close();	// 关闭连接
			}
			catch (Exception e) {
				log.error(e.getMessage());
			}
			finally {
				m.release();
			}
		}
		
		@Override
		public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
			// TODO Auto-generated method stub
			log.info("客户端exceptionCaught被调用");
			cause.printStackTrace();
			ctx.close();
		}
	}
	
    // 客户端请求处理对象
    private class RChildHandler extends ChannelInitializer<SocketChannel>{
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            ChannelPipeline pipeline = socketChannel.pipeline();
            pipeline.addLast(new IdleStateHandler(60, 60, 80));
            pipeline.addLast(new RClientHandler());
        }
    }
	
    // 发送消息到服务器，并且获取应答String
	public ByteBuf send(ByteBuf sendMsg) {
		boolean iRet = true; 
		this.setSendMsg(sendMsg);
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap b = new Bootstrap();
			b.group(group)
			.channel(NioSocketChannel.class)
			.option(ChannelOption.TCP_NODELAY, true)
			.handler(new RChildHandler());
			
			ChannelFuture f = b.connect(host, port);
			f.channel().closeFuture().sync();
			
			log.info("通讯全部关闭");
		}
		catch (Exception e) {
			iRet = false;
		}
		finally {
			group.shutdownGracefully();
		}
		
		return (iRet==true)?this.getRecvMsg():null;
	}
}